/**
 * @file udpUtil.c
 * @brief Sorgente contenente le funzioni base per le comunicazini tramite protocollo UDP.
 *
 * Sono inserite le funzioni per la creazione del socket.
 *
 * @date Mar 26, 2012
 * @author Francesco Corvino
 */
#include "rscNet.h"
#include "../RscHost/rscApplication.h"
#include "../logproxy/logproxy.h"

#define LOG_NAME_UDPUTIL "udplog"

char defBuf[UDP_MAX_SIZE_PKT];

int UDP_getAddress(Address *addr,char *address,char *port){
	AddressInfo hints;
	memset(&(hints), 0, sizeof(AddressInfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;

	/// - Richiede le informazioni sul tipo di socket da apripre per poter comunicare
	AddressInfo *hostinfo;
	if ((getaddrinfo(address, port, &hints, &hostinfo)) != 0)  {
		return -1;
	}
	memcpy(addr,hostinfo->ai_addr, sizeof(Address));
	freeaddrinfo(hostinfo);
	return 1;
}

/**
 * @brief Invia un messaggio UDP per una determinata destinazione.
 *
 * @param c Connessione su cui scrivere il messaggio.
 * @param to Destinazione a cui inviare il messaggio.
 * @param msg Messaggio da inviare.
 *
 * @return Numero di bytes inviati.
 */
int UDP_sendMsgTo(Connection *c, Address * to, char *msg){
	char *msgtosend = msg;
	int numbytes, iPkt, restbytes = (int) strlen(msg);
	if(restbytes==0) return -1;
	int numpkt = (restbytes/UDP_MAX_SIZE_PKT) + 1;
	log_namedlevel(LOG_NAME_UDPUTIL, LOG_INFO_LEVEL,
			"Invio dei dati tramite socket UDP.. numero di paccetti = %d \n",numpkt);
	// controllo se la lunghezza dei byte da inviare supera la dimensione usuale dei pacchetti udp
	for(iPkt=0;iPkt<numpkt;iPkt++){
		if ((numbytes = sendto(c->sd, msgtosend, restbytes, 0,
				to, sizeof(Address))) == -1)  return -1;
		if(numbytes>0){
			restbytes-= numbytes;
			msgtosend+= numbytes;
		} else {
			perror("sendto");
			printf("Errore nella sendto\n");
			break;
		}
	}
	return numpkt;
}

/**
 * @brief Riceve un messaggio da un socket.
 *
 * @param c Connessione da cui ricevere il messaggio.
 * @param bufin Buffer dove scrivere il messaggio ricevuto.
 * @param maxBufin Dimensione massima del buffer.
 * @param from Indirizzo da cui ricevere i dati.
 *
 * @return numero di byte effettivamente ricevuti.
 */
int UDP_recvMsgFrom(Connection *c, char *bufin, int maxBufin, Address * from){
	socklen_t len = sizeof(Address);
	/* read a datagram from the socket (put result in bufin) */
	int n = recvfrom(c->sd, bufin, maxBufin, 0,from, &len);
	if(n>0){

	} else {
		perror("recvfrom");
		printf("Errore nella recvfrom\n");
	}
	return n;
}

void UDP_createConn(Connection *c,UDPConnection *uc){
	/// - Configura la connessione
	HiddenType_init(&(c->dataProtocol),uc,sizeof(UDPConnection));

	/// - Imposta i valori per creare il socket
	AddressInfo hints;
	memset(&(hints), 0, sizeof(AddressInfo));
	hints.ai_family = uc->ai_family;
	hints.ai_socktype = SOCK_DGRAM;

	/// - Richiede le informazioni sul tipo di socket da apripre per poter comunicare
	AddressInfo *res, *hostinfo;
	if ((getaddrinfo(c->address, c->port, &hints, &hostinfo)) != 0)  {
		return;
	}
	/// - Controlla i risultati ottenuti e apre il socket:
	for(res = hostinfo; res != NULL; res = res->ai_next) {
		/// + Provo ad aprire un socket
		if ((c->sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
			// operazione di apertura del socket fallita
			continue;
		}
		if(uc->isServer) if(bind(c->sd,res->ai_addr,res->ai_addrlen)==-1){
			close(c->sd);
			continue;
		}
		/// + Se il socket deve essere connesso prova ad effettuare l'operazione
		if(uc->isConnected) if(connect(c->sd,res->ai_addr,res->ai_addrlen)==-1){
			close(c->sd);
			continue;
		}
		/// + Termino le operazioni di ricerca se il socket aperto è valido
		break;
	}
	/// - Constrola se almeno un file descriptor è stato aperto
	if (res != NULL) {
		memcpy(&(c->addr), res->ai_addr,sizeof(Address));
	} else {
		c->sd = -1;
	}
	/// - Libera la memoria allocata per le informazioni sull'host
	free(hostinfo);
}
